package com.mpc.manager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import com.mpc.params.MainTabPageParams;
import com.mpc.utils.Log;

public class StaticizeManager {
    private final String TAG = StaticizeManager.class.getSimpleName();

    private static StaticizeManager sMgr = null;

    private StaticizeManager() {
    }

    public static StaticizeManager getInstance() {
        if (sMgr == null) {
            sMgr = new StaticizeManager();
        }
        return sMgr;
    }

    public void staticizeRequest(HttpServletRequest request,
            HttpServletResponse response, boolean welcomeRequest)
            throws ServletException, IOException {
        // http://localhost:8080/MPCGame/home_en.htm
        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpResp = (HttpServletResponse) response;
        PageManager pMgr = PageManager.getInstance();
        UriManager uMgr = UriManager.getInstance();

        if (welcomeRequest) {
            Log.d(TAG,
                    "welcomeRequest=true - httpReq URI : "
                            + httpReq.getRequestURI());
            String htmlPath = uMgr.path2HomeHtmlStorage(request);
            File file = new File(UriManager.PATH_2_WEBAPPS + htmlPath);

            if (isFileExists(file)) {
                pMgr.forwardToHtml(httpReq, httpResp, htmlPath);
            } else {
                if (!mkFile(file)) {
                    return;
                }
                String jspPath = uMgr.path2HomeJspStorage(request);
                StaticResponse staticResp = resp2StaticResp(response, file);
                _staticizeRequest(request, staticResp, jspPath);
            }

        } else {
            Log.d(TAG,
                    "welcomeRequest=false - httpReq URI : "
                            + httpReq.getRequestURI());
            if (!isUriValid(httpReq)) {
                pMgr.forwardToHtml(httpReq, httpResp,
                        PageManager.INDEX_PAGE_NOT_FOUND, null);
                return;
            }

            String htmlPath = uMgr.path2HtmlStorage(httpReq);
            File file = new File(UriManager.PATH_2_WEBAPPS + htmlPath);

            if (isFileExists(file)) {
                pMgr.forwardToHtml(httpReq, httpResp, htmlPath);
            } else {
                if (!mkFile(file)) {
                    return;
                }
                String query = uMgr.getQueryFromHtmlUri(request);
                String jspQuery = MainTabPageParams.parse(query, true)
                        .toQueryString(false);
                String jspPath = uMgr.path2JspStorage(httpReq);
                StaticResponse staticResp = resp2StaticResp(response, file);
                _staticizeRequest(request, staticResp, jspPath + "?" + jspQuery);
            }
        }
    }

    private boolean mkFile(File file) throws IOException {
        file.getParentFile().mkdirs();
        if (!file.createNewFile()) {
            Log.e(TAG, "create " + file + " failed !");
            return false;
        }
        return true;
    }

    private boolean isUriValid(HttpServletRequest request) {
        if (UriManager.getInstance().isValidHtmlUri(request)) {
            return true;
        } else {
            return false;
        }
    }

    private boolean isFileExists(File file) {
        if (file.exists() && file.length() < 2) {
            file.delete();
            return false;
        }

        if (file.exists()) {
            return true;
        } else {
            Log.d(TAG, "file : " + file.getAbsolutePath() + " not exists !");
            return false;
        }
    }

    private StaticResponse resp2StaticResp(HttpServletResponse response,
            File file) throws IOException {
        Log.d(TAG, "static to " + file.getAbsolutePath());

        StaticResponse statResp = new StaticResponse(response, file);
        statResp.setContentType("text/html; charset=utf-8");
        return statResp;
    }

    private void _staticizeRequest(HttpServletRequest request,
            StaticResponse response, String path) throws ServletException,
            IOException {
        String servletContext = request.getServletContext().getContextPath();
        RequestDispatcher dispatcher = request.getRequestDispatcher(path
                .replace(servletContext, ""));
        Log.d(TAG, "forward uri = " + path);
        if (dispatcher != null) {
            dispatcher.forward(request, response);
        } else {
            Log.d(TAG, "dispatcher == null !");
        }
        ((TwoWayWriter) response.getWriter()).closeStatic();
    }

    class TwoWayWriter extends PrintWriter {
        private PrintWriter staticizeFileWriter = null;

        public TwoWayWriter(PrintWriter originWriter, PrintWriter staticWriter) {
            super(originWriter);
            this.staticizeFileWriter = staticWriter;
        }

        @Override
        public void flush() {
            super.flush();
            staticizeFileWriter.flush();
        }

        public void closeStatic() {
            staticizeFileWriter.close();
        }

        @Override
        public void close() {
            super.close();
            staticizeFileWriter.close();
        }

        @Override
        public boolean checkError() {
            return super.checkError() || staticizeFileWriter.checkError();
        }

        @Override
        public void write(int c) {
            super.write(c);
            staticizeFileWriter.write(c);
            Log.d(TAG, "write call");
        }

        @Override
        public void write(char[] buf, int off, int len) {
            super.write(buf, off, len);
            staticizeFileWriter.write(buf, off, len);
        }

        @Override
        public void write(char[] buf) {
            super.write(buf);
            staticizeFileWriter.write(buf);
        }

        @Override
        public void write(String s, int off, int len) {
            super.write(s, off, len);
            staticizeFileWriter.write(s, off, len);
        }

        @Override
        public void write(String s) {
            super.write(s);
            staticizeFileWriter.write(s);
        }
    }

    class StaticResponse extends HttpServletResponseWrapper {
        private TwoWayWriter writer = null;
        private File fileStaticizeTo = null;

        public StaticResponse(HttpServletResponse response, File fileStaticizeTo) {
            super(response);
            this.fileStaticizeTo = fileStaticizeTo;
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            if (writer == null) {
                FileOutputStream fout = new FileOutputStream(fileStaticizeTo);
                OutputStreamWriter fwriter = new OutputStreamWriter(fout, "utf-8");
                PrintWriter originWriter = getResponse().getWriter();
                writer =new TwoWayWriter(originWriter, new PrintWriter(fwriter));
            }
            return writer;
        }
    }

}
